//------------------------------------------------------------------------------
// <copyright file="WebAdminPage.cs" company="Microsoft">
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// </copyright>
//------------------------------------------------------------------------------
using System;
using System.Collections;
using System.Collections.Specialized;
using System.Configuration;
using System.Globalization;
using System.Reflection;
using System.Security;
using System.Security.Permissions;
using System.Web.Configuration;
using System.Web.Hosting;
using System.Web.Security;
using System.Web.SessionState;
using System.Web.UI;
using System.Web.UI.WebControls;

namespace System.Web.Administration
{
    [AspNetHostingPermission(SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)]
    [AspNetHostingPermission(SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal)]
    public class WebAdminPage : Page
    {
        private const string APP_PATH = "WebAdminApplicationPath";
        private const string APP_PHYSICAL_PATH = "WebAdminPhysicalPath";
        private const string CURRENT_EXCEPTION = "WebAdminCurrentException";
        private const string CURRENT_PROVIDER = "WebAdminCurrentProvider";
        private const string CURRENT_ROLE = "WebAdminCurrentRoleName";
        private const string CURRENT_USER = "WebAdminCurrentUser";
        private const string CURRENT_USER_COLLECTION = "WebAdminUserCollection";
        private const string URL_STACK = "WebAdminUrlStack";
        private string _directionality;
        private NavigationBar _navigationBar = null;

        public WebAdminRemotingManager RemotingManager
        {
            get { return (WebAdminRemotingManager) Session["WebAdminRemotingManager"]; }
        }


        public string ApplicationPath
        {
            get { return (string) Session[APP_PATH]; }
        }

        protected virtual bool CanSetApplicationPath
        {
            get { return false; }
        }

        protected string CurrentProvider
        {
            get
            {
                var obj = (object) Session[CURRENT_PROVIDER];
                if (obj != null)
                {
                    return (string) Session[CURRENT_PROVIDER];
                }
                return String.Empty;
            }
            set { Session[CURRENT_PROVIDER] = value; }
        }

        protected string CurrentRequestUrl
        {
            get
            {
                var stack = (Stack) Session[URL_STACK];
                if (stack != null && stack.Count > 0)
                {
                    return (string) stack.Peek();
                }
                return string.Empty;
            }
        }

        protected string CurrentRole
        {
            get
            {
                var obj = (object) Session[CURRENT_ROLE];
                if (obj != null)
                {
                    return (string) Session[CURRENT_ROLE];
                }
                return String.Empty;
            }
            set { Session[CURRENT_ROLE] = value; }
        }

        protected string CurrentUser
        {
            get
            {
                object obj = (string) Session[CURRENT_USER];
                if (obj != null)
                {
                    return (string) Session[CURRENT_USER];
                }
                return String.Empty;
            }
            set { Session[CURRENT_USER] = value; }
        }

        public string Directionality
        {
            get
            {
                if (String.IsNullOrEmpty(_directionality))
                {
                    _directionality =
                        ((string) GetGlobalResourceObject("GlobalResources", "HtmlDirectionality")).ToLower();
                }
                return _directionality;
            }
        }

        public HorizontalAlign DirectionalityHorizontalAlign
        {
            get
            {
                if (Directionality == "rtl")
                {
                    return HorizontalAlign.Right;
                }
                else
                {
                    return HorizontalAlign.Left;
                }
            }
        }

        public Hashtable UserCollection
        {
            get
            {
                var table = (Hashtable) Session[CURRENT_USER_COLLECTION];
                if (table == null)
                {
                    Session[CURRENT_USER_COLLECTION] = table = new Hashtable();
                }
                return table;
            }
        }

        public NavigationBar NavigationBar
        {
            get { return _navigationBar; }
            set { _navigationBar = value; }
        }

        public string UnderscoreProductVersion
        {
            get { return Environment.Version.ToString(3).Replace(".", "_"); }
        }

        public object CallWebAdminHelperMethod(bool isMembership, string methodName, object[] parameters,
                                               Type[] paramTypes)
        {
            object returnObject = null;
            object tempObject = null;

            tempObject = RemotingManager.ConfigurationHelperInstance;
            if (tempObject != null)
            {
                string methodName2 = string.Empty;
                string typeFullName = WebAdminRemotingManager.AssemblyVersionString;
                if (isMembership)
                {
                    methodName2 = "CallMembershipProviderMethod";
                }
                else
                {
                    methodName2 = "CallRoleProviderMethod";
                }
                Type tempType = Type.GetType(typeFullName);

                BindingFlags allBindingFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
                MethodInfo method = tempType.GetMethod(methodName2, allBindingFlags);
                if (method != null)
                {
                    var newParameters = new object[] {methodName, parameters, paramTypes};
                    try
                    {
                        var returnArrayObj = (object[]) method.Invoke(tempObject, newParameters);
                        if (returnArrayObj != null)
                        {
                            returnObject = returnArrayObj[0];
                        }
                    }
                    catch (Exception ex)
                    {
                        if (ex.InnerException != null)
                        {
                            if (ex.InnerException.InnerException != null)
                            {
                                throw new WebAdminException(ex.InnerException.InnerException.Message);
                            }
                            else
                            {
                                throw new WebAdminException(ex.InnerException.Message);
                            }
                        }
                        else
                        {
                            throw new WebAdminException(ex.Message);
                        }
                    }
                }
            }

            return returnObject;
        }

        public VirtualDirectory GetVirtualDirectory(string virtualDir)
        {
            return RemotingManager.GetVirtualDirectory(virtualDir);
        }

        public void SaveConfig(System.Configuration.Configuration config)
        {
            RemotingManager.ShutdownTargetApplication();

            // check if session expired
            if (String.IsNullOrEmpty(ApplicationPath) || String.IsNullOrEmpty((string) Session[APP_PHYSICAL_PATH]))
            {
                Server.Transfer("~/home2.aspx");
            }

            config.Save(ConfigurationSaveMode.Minimal);
        }

        public static Exception GetCurrentException(HttpContext c)
        {
            return (Exception) c.Session[CURRENT_EXCEPTION];
        }

        public static void SetCurrentException(HttpContext c, Exception ex)
        {
            c.Session[CURRENT_EXCEPTION] = ex;
        }

        protected void ClearBadStackPage()
        {
            var stack = (Stack) Session[URL_STACK];
            if (stack == null || stack.Count < 2)
            {
                return;
            }
            stack.Pop(); // current url
            stack.Pop(); // prev url
            // push current url back on stack.
            if (string.Compare(CurrentRequestUrl, Request.CurrentExecutionFilePath) != 0)
            {
                PushRequestUrl(Request.CurrentExecutionFilePath);
            }
        }

        public void ClearUserCollection()
        {
            Session[CURRENT_USER_COLLECTION] = null;
        }

        public static string GetParentPath(string path)
        {
            if (String.IsNullOrEmpty(path) || path[0] != '/')
                return null;

            int index = path.LastIndexOf('/');
            if (index < 0)
                return null;

            // parent for the root app is machine.config (null)
            if (path == "/")
                return null;

            string returnPath = path.Substring(0, index);
            if (returnPath.Length == 0 || returnPath == "/")
            {
                // for cassini, if returning /
                // then return null instead.
                returnPath = null;
            }

            return returnPath;
        }

        protected string GetQueryStringAppPath()
        {
            return Request.QueryString["applicationUrl"];
        }

        protected string GetQueryStringPhysicalAppPath()
        {
            return Request.QueryString["applicationPhysicalPath"];
        }

        public bool IsRoleManagerEnabled()
        {
            try
            {
                RoleManagerSection roleSection = null;
                System.Configuration.Configuration config = OpenWebConfiguration(ApplicationPath);
                roleSection = (RoleManagerSection) config.GetSection("system.web/roleManager");
                return roleSection.Enabled;
            }
            catch
            {
                return false;
            }
        }

        public bool IsRuleValid(BaseValidator placeHolderValidator, RadioButton userRadio, TextBox userName,
                                RadioButton roleRadio, DropDownList roles)
        {
            if (userRadio.Checked && userName.Text.Trim().Length == 0)
            {
                placeHolderValidator.ErrorMessage =
                    ((string) GetGlobalResourceObject("GlobalResources", "NonemptyUser"));
                placeHolderValidator.IsValid = false;
                return false;
            }
            if (roleRadio.Checked && roles.SelectedItem == null)
            {
                placeHolderValidator.ErrorMessage =
                    ((string) GetGlobalResourceObject("GlobalResources", "NonemptyRole"));
                placeHolderValidator.IsValid = false;
                return false;
            }
            if (userRadio.Checked)
            {
                string userNameString = userName.Text.Trim();
                if (-1 != userNameString.IndexOf('*'))
                {
                    placeHolderValidator.ErrorMessage =
                        ((string) GetGlobalResourceObject("GlobalResources", "InvalidRuleName"));
                    placeHolderValidator.IsValid = false;
                    return false;
                }
            }
            return true;
        }

        public bool IsWindowsAuth()
        {
            System.Configuration.Configuration config = OpenWebConfiguration(ApplicationPath);
            var auth = (AuthenticationSection) config.GetSection("system.web/authentication");
            return auth.Mode == AuthenticationMode.Windows;
        }

        protected void ItemDataBound(object sender, DataGridItemEventArgs e)
        {
            ListItemType itemType = e.Item.ItemType;
            if ((itemType == ListItemType.Pager) ||
                (itemType == ListItemType.Header) ||
                (itemType == ListItemType.Footer))
            {
                return;
            }
            foreach (Control c in e.Item.Cells[0].Controls)
            {
                var button = c as LinkButton;
                if (button == null)
                {
                    continue;
                }
                e.Item.Attributes["onclick"] = GetPostBackClientHyperlink(button, String.Empty);
            }
        }

        public System.Configuration.Configuration OpenWebConfiguration(string path)
        {
            return OpenWebConfiguration(path, false);
        }

        public System.Configuration.Configuration OpenWebConfiguration(string path, bool getWebConfigForSubDir)
        {
            var appPhysPath = (string) Session[APP_PHYSICAL_PATH];
            return OpenWebConfiguration(path, appPhysPath, getWebConfigForSubDir);
        }

        private System.Configuration.Configuration OpenWebConfiguration(string path, string appPhysPath,
                                                                        bool getWebConfigForSubDir)
        {
            // check if session expired
            if (String.IsNullOrEmpty(ApplicationPath) || String.IsNullOrEmpty((string) Session[APP_PHYSICAL_PATH]))
            {
                Server.Transfer("~/home2.aspx");
            }

            if (String.IsNullOrEmpty(path))
            {
                return WebConfigurationManager.OpenWebConfiguration(null);
            }

            var appVPath = (string) Session[APP_PATH];
            if (!getWebConfigForSubDir)
            {
                appVPath = path;
            }

            var fileMap = new WebConfigurationFileMap();
            fileMap.VirtualDirectories.Add(appVPath, new VirtualDirectoryMapping(appPhysPath, true));
            return WebConfigurationManager.OpenMappedWebConfiguration(fileMap, path);
        }

        protected override void OnInit(EventArgs e)
        {
            string applicationPath = ApplicationPath;
            string queryStringAppPath = GetQueryStringAppPath();
            string applicationPhysicalPath = GetQueryStringPhysicalAppPath();
            string requestAppPath = HttpContext.Current.Request.ApplicationPath;
            string currExFilePath = Request.CurrentExecutionFilePath;

            if (applicationPhysicalPath != null)
            {
                string webAdminVersion = "aspnet_webadmin\\" + UnderscoreProductVersion + "\\";
                if (applicationPhysicalPath.EndsWith(webAdminVersion))
                {
                    queryStringAppPath = requestAppPath;
                }
            }

            SetApplicationPath();

            if (string.Compare(CurrentRequestUrl, Request.CurrentExecutionFilePath) != 0)
            {
                PushRequestUrl(Request.CurrentExecutionFilePath);
            }

            base.OnInit(e);
        }

        protected void PopulateRepeaterDataSource(Repeater repeater)
        {
            // display alphabet row only if language is has Alphabet resource
            var arr = new ArrayList();
            var chars = ((string) GetGlobalResourceObject("GlobalResources", "Alphabet"));
            foreach (String s in chars.Split(';'))
            {
                arr.Add(s);
            }
            if (arr.Count == 0)
            {
                repeater.Visible = false;
            }
            else
            {
                arr.Add((string) GetGlobalResourceObject("GlobalResources", "All"));
                repeater.DataSource = arr;
                repeater.Visible = true;
            }
        }

        protected string PopPrevRequestUrl()
        {
            var stack = (Stack) Session[URL_STACK];
            if (stack == null || stack.Count < 2)
            {
                return string.Empty;
            }
            stack.Pop(); // discard current url
            return (string) stack.Pop();
        }

        protected void PushRequestUrl(string s)
        {
            var stack = (Stack) Session[URL_STACK];
            if (stack == null)
            {
                Session[URL_STACK] = stack = new Stack();
            }
            stack.Push(s);
        }

        protected void ReturnToPreviousPage(object sender, EventArgs e)
        {
            string prevRequest = PopPrevRequestUrl();
            Response.Redirect(prevRequest, false); // note: string.Empty ok here.
        }

        protected void RetrieveLetter(object sender, RepeaterCommandEventArgs e, GridView dataGrid)
        {
            RetrieveLetter(sender, e, dataGrid, (string) GetGlobalResourceObject("GlobalResources", "All"));
        }

        protected void RetrieveLetter(object sender, RepeaterCommandEventArgs e, GridView dataGrid, string all)
        {
            RetrieveLetter(sender, e, dataGrid, all, null);
        }

        protected void RetrieveLetter(object sender, RepeaterCommandEventArgs e, GridView dataGrid, string all,
                                      MembershipUserCollection users)
        {
            dataGrid.PageIndex = 0;
            int total = 0;
            string arg = e.CommandArgument.ToString();

            if (arg == all)
            {
                dataGrid.DataSource = (users == null)
                                          ? (MembershipUserCollection)
                                            CallWebAdminHelperMethod(true, "GetAllUsers",
                                                                     new object[] {0, Int32.MaxValue, total},
                                                                     new Type[]
                                                                         {
                                                                             typeof (int), typeof (int),
                                                                             Type.GetType("System.Int32&")
                                                                         })
                                          : users;
            }
            else
            {
                dataGrid.DataSource =
                    (MembershipUserCollection)
                    CallWebAdminHelperMethod(true, "FindUsersByName",
                                             new object[] {(string) arg + "%", 0, Int32.MaxValue, total},
                                             new Type[]
                                                 {
                                                     typeof (string), typeof (int), typeof (int),
                                                     Type.GetType("System.Int32&")
                                                 });
            }
            dataGrid.DataBind();
        }

        protected void SetApplicationPath()
        {
            if (!VerifyAppValid())
            {
                Server.Transfer("~/error.aspx");
            }
        }

        // At point when app is set, verify it is valid (i.e., permissions are proper and app exists).
        private bool VerifyAppValid()
        {
            // check if session expired
            if (String.IsNullOrEmpty(ApplicationPath) || String.IsNullOrEmpty((string) Session[APP_PHYSICAL_PATH]))
            {
                Server.Transfer("~/home2.aspx");
            }

            try
            {
                System.Configuration.Configuration config = OpenWebConfiguration(ApplicationPath);
                SaveConfig(config);
            }
            catch (Exception e)
            {
                var ex = new Exception((string) e.ToString());
                SetCurrentException(Context, ex);
                return false;
            }
            return true;
        }
    }

    [AspNetHostingPermission(SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)]
    [AspNetHostingPermission(SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal)]
    public sealed class WebAdminModule : IHttpModule
    {
        private const string APP_PATH = "WebAdminApplicationPath";
        private const string APP_PHYSICAL_PATH = "WebAdminPhysicalPath";
        private const string REMOTING_MANAGER = "WebAdminRemotingManager";

        #region IHttpModule Members

        public void Init(HttpApplication application)
        {
            application.Error += (new EventHandler(ApplicationError));
            application.AcquireRequestState += new EventHandler(OnEnter);
        }

        public void Dispose()
        {
        }

        #endregion

        private void ApplicationError(object sender, EventArgs e)
        {
            Exception exception = ((HttpApplication) sender).Server.GetLastError().InnerException;
            HttpContext context = ((HttpApplication) sender).Context;
            string redirectUrl = "~/error.aspx";
            if (String.IsNullOrEmpty(redirectUrl))
            {
                return;
            }

            WebAdminPage.SetCurrentException(context, exception);

            ((HttpApplication) sender).Server.Transfer(String.Format(CultureInfo.InvariantCulture, redirectUrl), true);
        }

        private void OnEnter(Object sender, EventArgs eventArgs)
        {
            var application = (HttpApplication) sender;

            if (!application.Context.Request.IsLocal)
            {
                var securityException =
                    new SecurityException(
                        (string)
                        HttpContext.GetGlobalResourceObject("GlobalResources", "WebAdmin_ConfigurationIsLocalOnly"));
                WebAdminPage.SetCurrentException(application.Context, securityException);
                application.Server.Transfer("~/error.aspx");
            }

            if (application != null)
            {
                SetSessionVariables(application);
            }
            application.Response.Cache.SetCacheability(HttpCacheability.NoCache);
        }

        private void SetSessionVariables(HttpApplication application)
        {
            string queryStringAppPath = string.Empty;
            string queryStringApplicationPhysicalPath = string.Empty;
            string applicationPath = string.Empty;
            string applicationPhysicalPath = string.Empty;
            string setAppPath = string.Empty;
            string setAppPhysPath = string.Empty;

            try
            {
                var permission = new SecurityPermission(PermissionState.Unrestricted);
                permission.Demand();
            }
            catch
            {
                var permissionException =
                    new Exception((string) HttpContext.GetGlobalResourceObject("GlobalResources", "FullTrustRequired"));
                WebAdminPage.SetCurrentException(application.Context, permissionException);
                application.Server.Transfer("~/error.aspx");
            }

            if (application.Context.Request != null)
            {
                queryStringAppPath = (string) application.Context.Request.QueryString["applicationUrl"];
                queryStringApplicationPhysicalPath =
                    (string) application.Context.Request.QueryString["applicationPhysicalPath"];
            }

            if (application.Context.Session != null)
            {
                if (application.Context.Session[APP_PATH] != null)
                {
                    applicationPath = (string) application.Context.Session[APP_PATH];
                }
                if (application.Context.Session[APP_PHYSICAL_PATH] != null)
                {
                    applicationPhysicalPath = (string) application.Context.Session[APP_PHYSICAL_PATH];
                }
            }

            if ((String.IsNullOrEmpty(queryStringAppPath) && applicationPath == null) ||
                (String.IsNullOrEmpty(queryStringApplicationPhysicalPath) && applicationPhysicalPath == null))
            {
                application.Server.Transfer("~/home0.aspx", false);
                return;
            }

            if (!String.IsNullOrEmpty(queryStringAppPath))
            {
                setAppPath = queryStringAppPath;
            }
            else if (!String.IsNullOrEmpty(applicationPath))
            {
                setAppPath = applicationPath;
            }

            if (!String.IsNullOrEmpty(queryStringApplicationPhysicalPath))
            {
                setAppPhysPath = queryStringApplicationPhysicalPath;
            }
            else if (!String.IsNullOrEmpty(applicationPhysicalPath))
            {
                setAppPhysPath = applicationPhysicalPath;
            }

            if (application.Context.Session != null)
            {
                application.Context.Session[APP_PATH] = setAppPath;
                application.Context.Session[APP_PHYSICAL_PATH] = setAppPhysPath;
                application.Context.Session[REMOTING_MANAGER] = new WebAdminRemotingManager(setAppPath, setAppPhysPath,
                                                                                            application.Context.Session);
            }
        }
    }

    public sealed class WebAdminMembershipProvider : MembershipProvider
    {
        public WebAdminMembershipProvider()
        {
        }

        public WebAdminRemotingManager RemotingManager
        {
            get { return (WebAdminRemotingManager) HttpContext.Current.Session["WebAdminRemotingManager"]; }
        }

        public override string ApplicationName
        {
            get { return (string) GetWebAdminMembershipProviderHelperProperty("ApplicationName"); }
            set { ; }
        }

        public override bool EnablePasswordRetrieval
        {
            get { return (bool) GetWebAdminMembershipProviderHelperProperty("EnablePasswordRetrieval"); }
        }

        public override bool EnablePasswordReset
        {
            get { return (bool) GetWebAdminMembershipProviderHelperProperty("EnablePasswordReset"); }
        }

        public override bool RequiresQuestionAndAnswer
        {
            get { return (bool) GetWebAdminMembershipProviderHelperProperty("RequiresQuestionAndAnswer"); }
        }

        public override bool RequiresUniqueEmail
        {
            get { return (bool) GetWebAdminMembershipProviderHelperProperty("RequiresUniqueEmail"); }
        }

        public override int MaxInvalidPasswordAttempts
        {
            get { return (int) GetWebAdminMembershipProviderHelperProperty("MaxInvalidPasswordAttempts"); }
        }

        public override int PasswordAttemptWindow
        {
            get { return (int) GetWebAdminMembershipProviderHelperProperty("PasswordAttemptWindow"); }
        }

        public override MembershipPasswordFormat PasswordFormat
        {
            get { return (MembershipPasswordFormat) GetWebAdminMembershipProviderHelperProperty("PasswordFormat"); }
        }

        public override int MinRequiredPasswordLength
        {
            get { return (int) GetWebAdminMembershipProviderHelperProperty("MinRequiredPasswordLength"); }
        }

        public override int MinRequiredNonAlphanumericCharacters
        {
            get { return (int) GetWebAdminMembershipProviderHelperProperty("MinRequiredNonAlphanumericCharacters"); }
        }

        public override string PasswordStrengthRegularExpression
        {
            get { return (string) GetWebAdminMembershipProviderHelperProperty("PasswordStrengthRegularExpression"); }
        }

        public object CallWebAdminMembershipProviderHelperMethod(string methodName, object[] parameters,
                                                                 Type[] paramTypes)
        {
            object returnObject = null;
            object tempObject = null;

            tempObject = RemotingManager.ConfigurationHelperInstance;
            if (tempObject != null)
            {
                string typeFullName = WebAdminRemotingManager.AssemblyVersionString;
                Type tempType = Type.GetType(typeFullName);

                BindingFlags allBindingFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
                MethodInfo method = tempType.GetMethod("CallMembershipProviderMethod", allBindingFlags);
                if (method != null)
                {
                    var newParameters = new object[] {methodName, parameters, paramTypes};
                    var returnArrayObj = (object[]) method.Invoke(tempObject, newParameters);
                    if (returnArrayObj != null)
                    {
                        returnObject = returnArrayObj[0];
                    }
                }
            }

            return returnObject;
        }

        public object[] CallWebAdminMembershipProviderHelperMethodOutParams(string methodName, object[] parameters,
                                                                            Type[] paramTypes)
        {
            var returnObjectArray = new object[0];

            object tempObject = RemotingManager.ConfigurationHelperInstance;
            if (tempObject != null)
            {
                string typeFullName = WebAdminRemotingManager.AssemblyVersionString;
                Type tempType = Type.GetType(typeFullName);

                BindingFlags allBindingFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
                MethodInfo method = tempType.GetMethod("CallMembershipProviderMethod", allBindingFlags);
                if (method != null)
                {
                    var newParameters = new object[] {methodName, parameters, paramTypes};
                    var returnArrayObj = (object[]) method.Invoke(tempObject, newParameters);
                    if (returnArrayObj != null)
                    {
                        returnObjectArray = returnArrayObj;
                    }
                }
            }

            return returnObjectArray;
        }

        public object GetWebAdminMembershipProviderHelperProperty(string propertyName)
        {
            object returnObject = null;
            object tempObject = null;
            tempObject = RemotingManager.ConfigurationHelperInstance;
            if (tempObject != null)
            {
                string typeFullName = WebAdminRemotingManager.AssemblyVersionString;
                Type tempType = Type.GetType(typeFullName);

                BindingFlags allBindingFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
                MethodInfo method = tempType.GetMethod("GetMembershipProviderProperty", allBindingFlags);
                if (method != null)
                {
                    var newParameters = new object[] {propertyName};
                    returnObject = method.Invoke(tempObject, newParameters);
                }
            }

            return returnObject;
        }

        public override bool ChangePassword(string name, string oldPwd, string newPwd)
        {
            return
                (bool)
                CallWebAdminMembershipProviderHelperMethod("ChangePassword", new object[] {name, oldPwd, newPwd},
                                                           new Type[]
                                                               {typeof (string), typeof (string), typeof (string)});
        }

        public override bool ChangePasswordQuestionAndAnswer(string name, string password, string newPwdQuestion,
                                                             string newPwdAnswer)
        {
            return
                (bool)
                CallWebAdminMembershipProviderHelperMethod("ChangePasswordQuestionAndAnswer",
                                                           new object[] {name, password, newPwdQuestion, newPwdAnswer},
                                                           new Type[]
                                                               {
                                                                   typeof (string), typeof (string), typeof (string),
                                                                   typeof (string)
                                                               });
        }

        public override MembershipUser CreateUser(string username,
                                                  string password,
                                                  string email,
                                                  string passwordQuestion,
                                                  string passwordAnswer,
                                                  bool isApproved,
                                                  object providerUserKey,
                                                  out MembershipCreateStatus status)
        {
            MembershipUser TempUser = null;
            status = MembershipCreateStatus.InvalidUserName;
            string typeFullName = "System.Web.Security.MembershipCreateStatus&, " +
                                  typeof (HttpContext).Assembly.GetName().ToString();
            Type tempType = Type.GetType(typeFullName);

            object[] returnAndOutParams = CallWebAdminMembershipProviderHelperMethodOutParams("CreateUser",
                                                                                              new object[]
                                                                                                  {
                                                                                                      username, password,
                                                                                                      email,
                                                                                                      passwordQuestion,
                                                                                                      passwordAnswer,
                                                                                                      isApproved,
                                                                                                      providerUserKey,
                                                                                                      status
                                                                                                  },
                                                                                              new Type[]
                                                                                                  {
                                                                                                      typeof (string),
                                                                                                      typeof (string),
                                                                                                      typeof (string),
                                                                                                      typeof (string),
                                                                                                      typeof (string),
                                                                                                      typeof (bool),
                                                                                                      typeof (object),
                                                                                                      tempType
                                                                                                  });
            if (returnAndOutParams != null)
            {
                TempUser = (MembershipUser) returnAndOutParams[0];
                status = (MembershipCreateStatus) returnAndOutParams[8];
            }

            if (status != MembershipCreateStatus.Success)
            {
                return null;
            }
            else
            {
                return TempUser;
            }
        }

        public override bool DeleteUser(string name, bool deleteAllRelatedContent)
        {
            return
                (bool)
                CallWebAdminMembershipProviderHelperMethod("DeleteUser", new object[] {name, deleteAllRelatedContent},
                                                           new Type[] {typeof (string), typeof (bool)});
        }

        public override MembershipUserCollection GetAllUsers(int pageIndex, int pageSize, out int totalRecords)
        {
            totalRecords = 0;
            var TempList =
                (MembershipUserCollection)
                CallWebAdminMembershipProviderHelperMethod("GetAllUsers",
                                                           new object[] {pageIndex, pageSize, totalRecords},
                                                           new Type[]
                                                               {
                                                                   typeof (int), typeof (int),
                                                                   Type.GetType("System.Int32&")
                                                               });
            var NewList = new MembershipUserCollection();
            foreach (MembershipUser TempItem in TempList)
            {
                var NewUser = new MembershipUser(Name,
                                                 TempItem.UserName,
                                                 TempItem.ProviderUserKey,
                                                 TempItem.Email,
                                                 TempItem.PasswordQuestion,
                                                 TempItem.Comment,
                                                 TempItem.IsApproved,
                                                 TempItem.IsLockedOut,
                                                 TempItem.CreationDate,
                                                 TempItem.LastLoginDate,
                                                 TempItem.LastActivityDate,
                                                 TempItem.LastPasswordChangedDate,
                                                 TempItem.LastLockoutDate);

                NewList.Add(NewUser);
            }

            return NewList;
        }

        public override MembershipUserCollection FindUsersByEmail(string emailToMatch, int pageIndex, int pageSize,
                                                                  out int totalRecords)
        {
            totalRecords = 0;
            var TempList =
                (MembershipUserCollection)
                CallWebAdminMembershipProviderHelperMethod("FindUsersByEmail",
                                                           new object[]
                                                               {emailToMatch, pageIndex, pageSize, totalRecords},
                                                           new Type[]
                                                               {
                                                                   typeof (string), typeof (int), typeof (int),
                                                                   Type.GetType("System.Int32&")
                                                               });
            var NewList = new MembershipUserCollection();
            foreach (MembershipUser TempItem in TempList)
            {
                var NewUser = new MembershipUser(Name,
                                                 TempItem.UserName,
                                                 TempItem.ProviderUserKey,
                                                 TempItem.Email,
                                                 TempItem.PasswordQuestion,
                                                 TempItem.Comment,
                                                 TempItem.IsApproved,
                                                 TempItem.IsLockedOut,
                                                 TempItem.CreationDate,
                                                 TempItem.LastLoginDate,
                                                 TempItem.LastActivityDate,
                                                 TempItem.LastPasswordChangedDate,
                                                 TempItem.LastLockoutDate);

                NewList.Add(NewUser);
            }

            return NewList;
        }

        public override int GetNumberOfUsersOnline()
        {
            return (int) CallWebAdminMembershipProviderHelperMethod("GetNumberOfUsersOnline", new object[] {}, null);
        }

        public override string GetPassword(string name, string answer)
        {
            return
                (string)
                CallWebAdminMembershipProviderHelperMethod("GetPassword", new object[] {name, answer},
                                                           new Type[] {typeof (string), typeof (string)});
        }

        public override MembershipUser GetUser(string name, bool userIsOnline)
        {
            var TempUser =
                (MembershipUser)
                CallWebAdminMembershipProviderHelperMethod("GetUser", new object[] {name, userIsOnline},
                                                           new Type[] {typeof (string), typeof (bool)});
            var NewUser = new MembershipUser(Name,
                                             TempUser.UserName,
                                             TempUser.ProviderUserKey,
                                             TempUser.Email,
                                             TempUser.PasswordQuestion,
                                             TempUser.Comment,
                                             TempUser.IsApproved,
                                             TempUser.IsLockedOut,
                                             TempUser.CreationDate,
                                             TempUser.LastLoginDate,
                                             TempUser.LastActivityDate,
                                             TempUser.LastPasswordChangedDate,
                                             TempUser.LastLockoutDate);

            return NewUser;
        }

        public override string GetUserNameByEmail(string email)
        {
            return
                (string)
                CallWebAdminMembershipProviderHelperMethod("GetUserNameByEmail", new object[] {email},
                                                           new Type[] {typeof (string)});
        }

        public override string ResetPassword(string name, string answer)
        {
            return
                (string)
                CallWebAdminMembershipProviderHelperMethod("ResetPassword", new object[] {name, answer},
                                                           new Type[] {typeof (string), typeof (string)});
        }

        public override void UpdateUser(MembershipUser user)
        {
            string typeFullName = "System.Web.Security.MembershipUser, " +
                                  typeof (HttpContext).Assembly.GetName().ToString();
            ;
            Type tempType = Type.GetType(typeFullName);

            CallWebAdminMembershipProviderHelperMethod("UpdateUser", new object[] {(MembershipUser) user},
                                                       new Type[] {tempType});
        }

        public override bool ValidateUser(string name, string password)
        {
            return
                (bool)
                CallWebAdminMembershipProviderHelperMethod("ValidateUser", new object[] {name, password},
                                                           new Type[] {typeof (string), typeof (string)});
        }

        public override MembershipUser GetUser(object providerUserKey, bool userIsOnline)
        {
            return
                (MembershipUser)
                CallWebAdminMembershipProviderHelperMethod("GetUser", new object[] {providerUserKey, userIsOnline},
                                                           new Type[] {typeof (object), typeof (bool)});
        }

        public override bool UnlockUser(string name)
        {
            return
                (bool)
                CallWebAdminMembershipProviderHelperMethod("UnlockUser", new object[] {name},
                                                           new Type[] {typeof (string)});
        }

        public override void Initialize(string name, NameValueCollection config)
        {
            if (String.IsNullOrEmpty(name))
            {
                name = "WebAdminMembershipProvider";
            }

            base.Initialize(name, config);
        }

        public override MembershipUserCollection FindUsersByName(string usernameToMatch, int pageIndex, int pageSize,
                                                                 out int totalRecords)
        {
            totalRecords = 0;
            var TempList =
                (MembershipUserCollection)
                CallWebAdminMembershipProviderHelperMethod("FindUsersByName",
                                                           new object[]
                                                               {usernameToMatch, pageIndex, pageSize, totalRecords},
                                                           new Type[]
                                                               {
                                                                   typeof (string), typeof (int), typeof (int),
                                                                   Type.GetType("System.Int32&")
                                                               });
            var NewList = new MembershipUserCollection();
            foreach (MembershipUser TempItem in TempList)
            {
                var NewUser = new MembershipUser(Name,
                                                 TempItem.UserName,
                                                 TempItem.ProviderUserKey,
                                                 TempItem.Email,
                                                 TempItem.PasswordQuestion,
                                                 TempItem.Comment,
                                                 TempItem.IsApproved,
                                                 TempItem.IsLockedOut,
                                                 TempItem.CreationDate,
                                                 TempItem.LastLoginDate,
                                                 TempItem.LastActivityDate,
                                                 TempItem.LastPasswordChangedDate,
                                                 TempItem.LastLockoutDate);

                NewList.Add(NewUser);
            }

            return NewList;
        }
    }

    public sealed class WebAdminRemotingManager : MarshalByRefObject
    {
        private static string _assemblyVersion;
        private string _applicationMetaPath;
        private string _applicationPhysicalPath;
        private ApplicationManager _appManager;
        private object _configurationHelper;
        private HttpSessionState _session;

        public WebAdminRemotingManager(string applicationMetaPath, string applicationPhysicalPath,
                                       HttpSessionState session)
        {
            _applicationMetaPath = applicationMetaPath;
            _applicationPhysicalPath = applicationPhysicalPath;
            _session = session;
        }

        public static string AssemblyVersionString
        {
            get
            {
                if (String.IsNullOrEmpty(_assemblyVersion))
                {
                    _assemblyVersion = "System.Web.Administration.WebAdminConfigurationHelper, " +
                                       typeof (HttpContext).Assembly.GetName().ToString();
                }
                return _assemblyVersion;
            }
        }

        private ApplicationManager AppManager
        {
            get
            {
                if (_appManager == null)
                {
                    return _appManager = ApplicationManager.GetApplicationManager();
                }
                return _appManager;
            }
        }

        protected string ApplicationMetaPath
        {
            get { return _applicationMetaPath; }
        }

        public string ApplicationPhysicalPath
        {
            get { return _applicationPhysicalPath; }
            set
            {
                _applicationPhysicalPath = value;
                // Set provider proxy references to null, to account for the edge case where ApplicationPhysicalPath is set twice.
                // Notes: this does not shut down the target appdomain, which is the desired behavior, since, in the unlikely case where the
                // ApplicationPhysicalPath is changed, the change is likely to be reverted.  Resetting the providers is necessary because
                // the existing providers point to the old target appdomain.
                ResetProviders();
            }
        }

        public object ConfigurationHelperInstance
        {
            get { return CreateConfigurationHelper(); }
        }

        private HttpSessionState Session
        {
            get { return _session; }
        }

        public string TargetAppId
        {
            get
            {
                if (Session["WebAdminTargetAppId"] != null)
                {
                    return (string) Session["WebAdminTargetAppId"];
                }
                else
                {
                    return string.Empty;
                }
            }
            set { Session["WebAdminTargetAppId"] = value; }
        }

        public override Object InitializeLifetimeService()
        {
            return null; // never expire lease
        }

        private object CreateConfigurationHelper()
        {
            if (_configurationHelper != null)
            {
                return _configurationHelper;
            }
            string appPath = ApplicationMetaPath;
            string appPhysPath = ApplicationPhysicalPath;
            string targetAppId = String.Empty;

            string typeFullName = AssemblyVersionString;
            Type tempType = Type.GetType(typeFullName);

            // Put together some unique app id
            string appId = (String.Concat(appPath, appPhysPath).GetHashCode()).ToString("x",
                                                                                        CultureInfo.InvariantCulture);

            _configurationHelper =
                (object)
                ApplicationManager.GetApplicationManager().CreateObject(appId, tempType, appPath, appPhysPath, false,
                                                                        true);
            TargetAppId = appId;

            return _configurationHelper;
        }

        private void EnsureTargetAppId()
        {
            if (TargetAppId != null)
            {
                return;
            }
            // In some cases, the target appdomain exists before the AppId is discovered by AppManager.CreateObjectWithDefaultAppHostAndAppId
            // (for example if the target app is already running).  In this case, retrieve one of the 
            // providers (we make an arbitrary choice to retrieve the membership provider).  This forces the object to 
            // discover the target appid.  

            CreateConfigurationHelper(); // Retrieves the target appid.
        }

        public VirtualDirectory GetVirtualDirectory(string virtualDir)
        {
            VirtualDirectory vdir = null;
            object configHelperObject = ConfigurationHelperInstance;
            if (configHelperObject != null)
            {
                string typeFullName = AssemblyVersionString;
                Type tempType = Type.GetType(typeFullName);

                BindingFlags allBindingFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
                MethodInfo method = tempType.GetMethod("GetVirtualDirectory", allBindingFlags);
                if (method != null)
                {
                    vdir = (VirtualDirectory) method.Invoke(configHelperObject, new object[] {virtualDir});
                }
            }

            return vdir;
        }

        public void ResetProviders()
        {
            _configurationHelper = null;
            TargetAppId = null;
        }

        public void ShutdownTargetApplication()
        {
            // CONSIDER: Rather than calling EnsureTargetAppId(), is there a method on AppManager that can tell us whether
            // an appdomain exists based on the Id, and another method that creates the "default Id" from the application 
            // path and physical path?  This prevents the following two lines from creating the appdomain and immediately 
            // shutting it down in the (edge) case where the target appdomain doesn't exist.

            EnsureTargetAppId();
            AppManager.ShutdownApplication(TargetAppId);

            // ResetProviders to ensure that the value of TargetAppId is in sync with the provider proxies.  Calling 
            // property get for a provider proxy sets TargetAppId to the correct value.
            ResetProviders();
        }
    }

    [AspNetHostingPermission(SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)]
    [AspNetHostingPermission(SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal)]
    public class WebAdminUserControl : UserControl
    {
        #region DatabaseType enum

        public enum DatabaseType
        {
            Access = 0,
            Sql = 1,
        }

        #endregion

        private string _directionality;

        public string Directionality
        {
            get
            {
                if (String.IsNullOrEmpty(_directionality))
                {
                    _directionality =
                        ((string) GetGlobalResourceObject("GlobalResources", "HtmlDirectionality")).ToLower();
                }
                return _directionality;
            }
        }

        public HorizontalAlign DirectionalityHorizontalAlign
        {
            get
            {
                if (Directionality == "rtl")
                {
                    return HorizontalAlign.Right;
                }
                else
                {
                    return HorizontalAlign.Left;
                }
            }
        }

        public virtual bool OnNext()
        {
            return true; // move to next control.  Override to return false if next should not be honored.
        }

        public virtual bool OnPrevious()
        {
            return true; // move to next control.  Override to return false if prev should not be honored.
        }
    }


    [Serializable]
    public class WebAdminException : Exception
    {
        public WebAdminException()
        {
        }

        public WebAdminException(string message)
            : base(message)
        {
        }
    }
}